package com.goldgov.code.template.commons.impl.order;

import java.io.StringWriter;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import com.goldgov.code.meta.FieldInfo;
import com.goldgov.code.meta.ModuleInfo;
import com.goldgov.code.template.Layout;
import com.goldgov.code.template.ParamKeyName;
import com.goldgov.code.template.commons.CommonPlugin;
import com.goldgov.code.template.impl.DaoLayout;
import com.goldgov.code.template.impl.ServiceLayout;
import com.goldgov.code.template.impl.WebLayout;
import com.goldgov.code.template.point.CodePoint;
import com.goldgov.code.template.point.PointMapping;
import com.goldgov.code.template.point.impl.InterfaceMethodCodePoint;
import com.goldgov.code.template.point.impl.MyBatisXmlCodePoint;
import com.goldgov.code.utils.FreemarkerUtils;

import freemarker.template.Template;

public class OrderByPlugin implements CommonPlugin{

	public static final String FIELD_NAME_ORDER_NUM = "ORDER_NUM";

	@Override
	public String name() {
		return "order";
	}

	@Override
	public PointMapping doLayout(ModuleInfo module, Layout[] layouts,Map<String,Object> paramMap) {
		PointMapping pointMapping = new PointMapping();
		
		Map<String,Object> extParam = (Map<String, Object>) paramMap.get("extParam");
		boolean genDefField = Boolean.valueOf(""+extParam.get(ParamKeyName.GEN_DEFAULT_FIELD));
		
		String stateCondition = "";
		if(genDefField) {
			stateCondition = " AND STATE=1\r\n";
		}
		
		for (Layout layout : layouts) {
			
			String getOrderNumMethod = "getOrderNum";
			String increaseOrderNumMethod = "increaseOrderNum";
			String updateOrderNumMethod = "updateOrderNum";
//			String decreaseOrderNumMethod = "decreaseOrderNum";
			String getMaxOrderNum = "getMaxOrderNum";
			String getIdByRow = "getIdByRow";
			if(layout instanceof DaoLayout) {
				List<CodePoint> codePointList = pointMapping.codePoint("*/*Dao.java.ftl");
				List<CodePoint> xmlPointList = pointMapping.codePoint("*/*Dao.xml.ftl");
				// Java Code
//				codePointList.add(new ImportCodePoint(Map.class));
				codePointList.add(new InterfaceMethodCodePoint(getOrderNumMethod,"Integer","@Param(\"id\") String id"));
				codePointList.add(new InterfaceMethodCodePoint(increaseOrderNumMethod,"@Param(\"parentID\") String parentID,@Param(\"from\") int from,@Param(\"to\") int to"));
//				codePointList.add(new InterfaceMethodCodePoint(decreaseOrderNumMethod,"@Param(\"parentID\") String parentID,@Param(\"from\") int from,@Param(\"to\") int to"));
				codePointList.add(new InterfaceMethodCodePoint(updateOrderNumMethod,"@Param(\"id\") String id,@Param(\"orderNum\") int orderNum"));
				codePointList.add(new InterfaceMethodCodePoint(getMaxOrderNum,"Integer","@Param(\"parentID\") String parentID"));
				codePointList.add(new InterfaceMethodCodePoint(getIdByRow,"String","@Param(\"parentID\") String parentID,@Param(\"row\") Integer row"));
				// MyBatis XML
				String pkFieldName = module.getPkField().getField();
				
				StringBuilder xmlBuilder = new StringBuilder();
				xmlBuilder.append(
						"	<update id=\"" + increaseOrderNumMethod + "\">\r\n" + 
						"		UPDATE " + module.getTableName() + "\r\n" + 
						"		SET ORDER_NUM = ORDER_NUM + 1\r\n" + 
						"		WHERE ORDER_NUM &gt;= #{from}" +
						"		<if test=\"to &gt; 0\"> AND ORDER_NUM &lt;= #{to}</if>\r\n" +
						"		<if test=\"parentID!=null and parentID != ''\">AND PARENT_ID=#{parentID}</if>\r\n" +
						"	</update>\r\n\r\n" + 
//						"	<update id=\"" + decreaseOrderNumMethod + "\">\r\n" + 
//						"		UPDATE TEST_TABLE\r\n" + 
//						"		SET ORDER_NUM = ORDER_NUM - 1\r\n" + 
//						"		WHERE ORDER_NUM &gt;= #{from} AND ORDER_NUM &lt;= #{to}\r\n" +
//						"		<if test=\"parentID!=null and parentID != ''\">AND PARENT_ID=#{parentID}</if>\r\n" +
//						"	</update>\r\n\r\n" +

						"	<select id=\"" + getIdByRow + "\" resultType=\"String\">\r\n" + 
						"		<bind name=\"nowNum\" value=\"row - 1\">\r\n/" +
						"		SELECT " +  pkFieldName  + " FROM " + module.getTableName() + " \r\n" +
						"		<if test=\"parentID!=null and parentID != ''\">WHERE PARENT_ID=#{parentID}</if>\r\n" +
						"		ORDER BY ORDER_NUM	LIMIT #{nowNum},1\r\n" +
						"	</select>\r\n\r\n" +
						
						"	<select id=\"getIdByRow\" resultType=\"String\" databaseId=\"Oracle\">\r\n" +
						"		SELECT t."+ pkFieldName + ", ROWNUM RNUM FROM (SELECT " + pkFieldName + " FROM " + module.getTableName() + " <if test=\"parentID!=null and parentID != ''\">WHERE PARENT_ID=#{parentID}</if> ORDER BY ORDER_NUM ) t  WHERE ROWNUM &lt;= #{row})  WHERE RNUM &gt;= #{row}" +
						"	</select>\r\n\r\n" +

						"	<select id=\"" + getOrderNumMethod + "\" resultType=\"Integer\">\r\n" + 
						"		SELECT ORDER_NUM as orderNum," + pkFieldName + " as id from " + module.getTableName() + " WHERE " + pkFieldName + " = #{id}\r\n" + 
						"	</select>\r\n\r\n" + 
						"	<select id=\"" + getMaxOrderNum + "\" resultType=\"Long\">\r\n" + 
						"		SELECT MAX(ORDER_NUM) FROM " + module.getTableName() + "\r\n" + 
						"		<where>\r\n" + stateCondition +
						"		<if test=\"parentID!=null and parentID != ''\">AND PARENT_ID=#{parentID}</if>\r\n" +
						"		</where>\r\n" +
						"	</select>\r\n\r\n" + 
						"	<update id=\"" + updateOrderNumMethod + "\">\r\n" + 
						"		UPDATE " + module.getTableName() + "\r\n" + 
						"		SET ORDER_NUM = #{orderNum}\r\n" + 
						"		WHERE " + pkFieldName + " = #{id}\r\n" + 
						"	</update>\r\n\r\n");
				xmlPointList.add(new MyBatisXmlCodePoint(xmlBuilder.toString()));
			}else if(layout instanceof ServiceLayout) {
				List<CodePoint> interfacePointList = pointMapping.codePoint("*/*Service.java.ftl");
				List<CodePoint> implPoint = pointMapping.codePoint("**/*ServiceImpl.java.ftl");
				String moveToIndexMethod = "moveToRow";
				// Service Interface
				interfacePointList.add(new InterfaceMethodCodePoint(moveToIndexMethod,"String parentID,int targetRow,String sourceID"));
				interfacePointList.add(new InterfaceMethodCodePoint(moveToIndexMethod,"String parentID,String targetID,String sourceID"));
				
				// Service Implement
//				implPoint.add(new ImportCodePoint(Map.class));
				Template template = FreemarkerUtils.getTemplate("orderBy/serviceImpl.ftl");
				StringWriter stringWriter = new StringWriter();
				Map<String,Object> dataMap = new HashMap<>();
				dataMap.put("module", module);
				try {
					template.process(dataMap, stringWriter);
					implPoint.add(new CodePoint("JAVA:METHOD") {
						@Override
						public String getCodes() {
							return stringWriter.toString();
						}});
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}else if(layout instanceof WebLayout) {
				List<CodePoint> webPointList = pointMapping.codePoint("*/*Controller.java.ftl");
				
				Template template = FreemarkerUtils.getTemplate("orderBy/controller.ftl");
				StringWriter stringWriter = new StringWriter();
				Map<String,Object> dataMap = new HashMap<>();
				dataMap.put("module", module);
				try {
					template.process(dataMap, stringWriter);
					webPointList.add(new CodePoint("JAVA:METHOD") {
						@Override
						public String getCodes() {
							return stringWriter.toString();
						}});
				} catch (Exception e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
			}
		}
		return pointMapping;
	}

	@Override
	public boolean supports(ModuleInfo module, Layout[] layouts) {
		FieldInfo[] fields = module.getFields();
		for (FieldInfo fieldInfo : fields) {
			if(fieldInfo.getField().equals(FIELD_NAME_ORDER_NUM)) {
				return true;
			}
		}
		return false;
	}
}
